import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Vector;

import javax.swing.DefaultListModel;

public class Wallet {

	private PropertyChangeSupport pcSupport = new PropertyChangeSupport(this);
	private BigDecimal balance;
	private Vector<Expense> expenseList;
	private Vector<Income> incomeList;
	private Vector<Bill> billList;

	private Salary salary;
	private Alert alert;
	private int itemIndex;

	// constructor
	public Wallet(BigDecimal balance, Vector<Expense> expenseList,
			Vector<Income> incomeList, Vector<Bill> billList, Salary salary,
			int index) {

		alert = new Alert();
		this.balance = balance;

		this.expenseList = expenseList;
		this.incomeList = incomeList;
		this.billList = billList;

		this.salary = salary;
		this.autoPaySalary();

		alert.print();

		this.itemIndex = index;
	}

	// allow addition of listeners or observers
	public void addPropertyChangeListener(PropertyChangeListener listener) {
		pcSupport.addPropertyChangeListener(listener);

	}

	// Operations for specific Income object (salary/miscellaneous income)
	// ===============================
	public Income addIncome(String description, Calendar date, BigDecimal amt,
			int row) {
		Income incomeToAdd = new Income(description, date, amt, itemIndex++);
		incomeList.insertElementAt(incomeToAdd, row);

		setBal(balance.add(amt));
		printBal();

		return incomeToAdd;
	}

	public void editIncome(String newDescription, Calendar newDate,
			BigDecimal newAmt, Income income) {
		if (!income.getAmt().equals(newAmt)) {
			setBal(balance.subtract(income.getAmt()));
			setBal(balance.add(newAmt));
		}

		income.set(newDescription, newDate, newAmt);
		printBal();
	}

	// row =/= index of item in vector. maybe should check
	public Income deleteIncome(int row) {
		setBal(balance.subtract(incomeList.get(row).getAmt()));
		Income removedIncome = incomeList.remove(row);
		printBal();

		return removedIncome;
	}

	// Operations for specific Expense object
	// ============================================================
	public Expense addExpense(String description, Calendar date,
			BigDecimal amt, String category, String paymentMethod, int row) {
		Expense expenseToAdd = new Expense(description, date, amt, category,
				paymentMethod, itemIndex++);
		expenseList.insertElementAt(expenseToAdd, row);

		setBal(balance.subtract(amt));
		printBal();

		return expenseToAdd;
	}

	public void editExpense(String newDescription, Calendar newDate,
			BigDecimal newAmt, String newCategory, String newPaymentMethod,
			Expense expense) {
		if (!expense.getAmt().equals(newAmt)) {
			setBal(balance.add(expense.getAmt()));
			setBal(balance.subtract(newAmt));
		}

		expense.set(newDescription, newDate, newAmt, newCategory,
				newPaymentMethod);
		printBal();
	}
	
	// row =/= index of item in vector. maybe should check
	public Expense deleteExpense(int row) {
		setBal(balance.add(expenseList.get(row).getAmt()));

		Expense expenseToRemove = expenseList.remove(row);

		printList();
		printBal();

		return expenseToRemove;
	}

	// Operations for bill(s)
	// ============================================================================
	public Bill addBill(String description, Calendar date, Calendar lastPaidDate, int row) {
		Bill billToAdd = new Bill(description, date, lastPaidDate, itemIndex++);

		billList.insertElementAt(billToAdd, row);

		return billToAdd;
	}

	/**
	 * Whenever a bill is paid, the alertList is regenerated
	 */
	public void payBill(Bill bill, Calendar date) {
		bill.payBill(date);
		alert.generateAlerts(billList);
	}
	
	public void editBill(String description, Calendar date, Calendar lastPaidDate, Bill bill) {
		bill.set(description, lastPaidDate);
	}

	// row =/= index of item in vector. maybe should check
	public Bill deleteBill(int row) {
		Bill billToRemove = billList.remove(row);
		return billToRemove;
	}

	// Operation for Salary (fixed salary that user keyed in when creating
	// profile)=======================
	/**
	 * This method is called every time the wallet is opened to check for and
	 * auto add new income from the salary.
	 */
	public void autoPaySalary() {
		Calendar today = Calendar.getInstance();
		String month;
		while (today.after(salary.getNextPayDate())) {
			month = salary.paySalary(today);
			this.addIncome("Salary for " + month, today, salary.getAmt(), 0);
		}

		alert.generateAlerts(billList);
	}

	// setter method below
	// ===============================================================================

	public void setBal(BigDecimal bal) {
		BigDecimal oldBal = balance;
		this.balance = bal;
		pcSupport.firePropertyChange("balance", oldBal, bal);
	}

	// getter method below
	// ===============================================================================
	public BigDecimal getBalance() {
		return balance;
	}

	public Vector<Expense> getExpenseList() {
		return expenseList;
	}

	public Vector<Income> getIncomeList() {
		return incomeList;
	}

	public Vector<Bill> getBillList() {
		return billList;
	}

	public Salary getSalary() {
		return salary;
	}

	public Alert getAlert() {
		alert.generateAlerts(billList);
		return alert;
	}

	public int getItemIndex() {
		return itemIndex;
	}

	// printing operations for debugging
	// =================================================================
	public void printBal() {
		System.out.println(">>Current balance: " + balance);
	}

	public void printList() {
		for (int i = 0; i < expenseList.size(); i++) {
			expenseList.get(i).print();
		}
	}
}